#!/usr/bin/env python
# -*- coding: utf-8 -*-

##########################################################################################
#####				L I C E N S E					     #####
##########################################################################################
#
#  GNU LESSER GENERAL PUBLIC LICENSE
#  Version 2.1, February 1999
#
#  Copyright (C) 1991, 1999 Free Software Foundation, Inc.
#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#  Everyone is permitted to copy and distribute verbatim copies
#  of this license document, but changing it is not allowed.
#
#  [This is the first released version of the Lesser GPL. It also counts
#  as the successor of the GNU Library Public License, version 2, hence
#  the version number 2.1.]
#
#  'AeroFoil' is a FreeCAD macro. AeroFoil creates airfoil curves and faces
#  using pre-defined models, algebraic functions, and DAT or CSV Files.
#
#  Copyright (C) 2021  Melwyn Francis Carlo
#
#  This library is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public
#  License as published by the Free Software Foundation; either
#  version 2.1 of the License, or (at your option) any later version.
#
#  This library is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public License
#  along with this library; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#  Contact Information :-
#  Email :  carlo.melwyn@outlook.com
#  FreeCAD UserTalk :  http://www.freecadweb.org/wiki/index.php?title=User:Melwyncarlo
#
##########################################################################################
#####				L I C E N S E					     #####
##########################################################################################
#
#
#
#  The AeroFoil macro was developed and tested on a platform containing the
#  following system and FreeCAD software specifications :
#
#  - OS			: Ubuntu 18.04.5 LTS (LXDE/Lubuntu)
#  - Word size of OS	: 64-bit
#  - Word size of FreeCAD: 64-bit
#  - Version		: 0.19
#  - Build type		: Release
#  - Branch		: unknown
#  - Hash		: 32200b604d421c4dad527fe587a7d047cf953b4f
#  - Python version	: 3.6.9
#  - Qt version		: 5.9.5
#  - Coin version	: 4.0.0a
#  - OCC version	: 7.3.0
#  - Locale		: English/UnitedKingdom (en_GB)


"""
  To use this macro, the steps to be followed are simple and straightforward :
  follow the instructions in the respective dialog boxes, fill in the relevant inputs,
  and navigate accordingly. In case of error or warning, you will automatically be
  notified the same. In case you are notified to report an unexpected error,
  communicate the error by mentioning the FreeCAD version, tracing the steps
  taken, and mentioning whether (and how much) or not any ouput was generated.

  Note (1)	Performing the macro operation with custom points and refinement
		produces no visible changes.
  Note (2)	The AeroFoil object properties are only visible on the FreeCAD
		software version 0.19. On older versions, you will be shown
		a warning on the console.
  Note (3)	The single underscore prefix (e.g. _name) denotes a private
		function or a private variable.
  Note (4)	Some of the short forms used in this script are as follows:
		  'af' stands for AeroFoil
  		  'mfb' stands for Math Functions Box
  		  'd' stands for Dialog (e.g. d2c, d3, etc.)
  Note (5)	The dialog boxes and their corresponding UI elements may be
		labelled differently. Here is a map:
		  d1	= AeroFoil_Initial_Dialog
		  d2a	= AeroFoil_NACA4Digit_Dialog
		  d2b	= AeroFoil_NACA5Digit_Dialog
		  d2c	= AeroFoil_CurvesInput_Dialog
		  d2d	= AeroFoil_PointsInput_Dialog
		  d2d1a	= AeroFoil_DATInput_Dialog
		  d2d1b	= AeroFoil_CSVInput_Dialog
		  dcd2	= AeroFoil_FileLoad_Dialog
		  d3	= AeroFoil_Final_Dialog
		  mfb	= AeroFoil_Math_Functions_Box
		Read the DocString of the '_setDialogIndex' method in the
		'AeroFoilDialog' class to know more about its implementation.
  Note (6)	The global variable 'dialogIndex' is listed in the exact order
		as the above list of dialog boxes.
"""

__Title__         = "AeroFoil"
__Author__        = "Melwyncarlo"
__Version__       = "2.0.3"
__Date__          = "2021-03-10"
__Comment__       = "AeroFoil creates airfoil curves and faces using pre-defined models, algebraic functions, and DAT or CSV Files"
__Web__           = "https://github.com/melwyncarlo/AeroFoil"
__Wiki__          = "http://www.freecadweb.org/wiki/index.php?title=Macro_AeroFoil"
__Icon__          = "AeroFoil.svg"
__Help__          = "Click on the AeroFoil button/macro, and follow the instructions in the subsequent dialog boxes."
__Status__        = "stable"
__Requires__      = "Freecad >= v0.17"
__License__       = "LGPL-2.1-or-later"
__Communication__ = "https://github.com/melwyncarlo/AeroFoil/issues"
__Files__         = "AeroFoil_UI_Files/AeroFoil_Initial_Dialog.ui,AeroFoil_UI_Files/AeroFoil_NACA4Digit_Dialog.ui,AeroFoil_UI_Files/AeroFoil_NACA5Digit_Dialog.ui,AeroFoil_UI_Files/AeroFoil_CurvesInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_PointsInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_DATInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_CSVInput_Dialog.ui,AeroFoil_UI_Files/AeroFoil_FileLoad_Dialog.ui,AeroFoil_UI_Files/AeroFoil_Final_Dialog.ui,AeroFoil_UI_Files/AeroFoil_Math_Functions_Box.ui,AeroFoil_UI_Files/AeroFoil_mfb_img.gif,AeroFoil.svg"

# Library Imports
# ------------------------------------------------------------------------------------------------

import FreeCAD as app
import FreeCADGui as gui
import Sketcher, Part, Draft
from pathlib import Path
import PySide
from PySide import QtGui, QtCore
from PySide.QtGui import *
from PySide.QtCore import *
import time, math, csv, re

###########################################################################
###---------------------------------------------------------------------###
### 		AEROFOIL MACRO CALLS - Top (check Bottom)		###
###---------------------------------------------------------------------###
                                                                        ###
def AeroFoil_generate(obj):						###
    """
    The 'AeroFoil_generate' function generates the 2D curves
    and shapes, assigns them properties, and creates
    multiples of created curves and shapes.

    Arguments
    ----------
    obj: An instance of the 'AeroFoilDialog' object.

    Return
    ----------
    True:   The airfoil curves/shapes were generated
            successfully.
    False:  The airfoil curves/shapes were NOT generated
            successfully.
    """									###
    n_ = (obj.multi * (obj.multiParam - 1)) + 1				###
    AeroFoil_object = AeroFoil(obj)					###
    if AeroFoil_object.create():					###
        AeroFoil_object.characterize()					###
    else:								###
        return False							###
    AeroFoil_object.copy(n_)						###
    return True								###
                                                                        ###
###---------------------------------------------------------------------###
### 		AEROFOIL MACRO CALLS - Top (check Bottom)		###
###---------------------------------------------------------------------###
###########################################################################



# Constant Variables
# ------------------------------------------------------------------------------------------------

MAX_REFINE_PARAM = 2
# Pertaining to the 'Refine Parameter' input from AeroFoil_Final_Dialog
# It is the maximum airfoil points refinement coefficient above which
# a warning is diplayed notifying the user of increased computation.
MAX_QUANTITY_PARAM = 5
# Pertaining to the 'Quantity Parameter' input from AeroFoil_Final_Dialog
# It is the maximum number of Airfoil curves to be generated above which
# a warning is diplayed notifying the user of increased computation.
MIN_DATA_POINTS = 10
# Pertaining to the 'Quantity Parameter' input from AeroFoil_FileLoad_Dialog
# It is the minimum pair of airfoil data points to be present in the file
# below which an error is shown.
NACA_NUMBER_OF_POINTS = 50
# It is the number of airfoil data points pair used while generating the curves
# It is the value set at REFINE_PARAM = 1
NACA_5_2ND_3RD_DIGITS = ["10", "20", "30", "40", "50", "21", "31", "41", "51"]
# The NACA 5 Digit airfoils are limited. These are the 2nd and 3rd digit combinations
# of the available NACA 5 Digit airfoils
FUNCTIONSARRAY = [
    "+",
    "-",
    "*",
    "/",
    "^",
    "e",
    "pi",
    "ln(",
    "log(",
    "sqrt(",
    "sin(",
    "cos(",
    "tan(",
    "asin(",
    "acos(",
    "atan(",
    "x",
    "(",
    ")",
    ".",
]
# A list of functions and mathematics-based characters that are allowed for input.
UNITSCONVERSION = [0, 1, 10, 1000, 25.4, 304.8, 914.4]
# This is the conversion coefficients list to convert different units into millimetres (mm).
# From element 2 to 7 :  millimetre (mm), centimetre (cm), metre (m), inch (in), feet (ft),
# and yards.
# Ignore the 1st element; it's superfluous.
MIN_CHORD_LENGTH_MM = 1
# It is the minimum airfoil chord length input below which a warning is displayed.
MACRO_DIR = app.getUserMacroDir(True) + "/AeroFoil_UI_Files/AeroFoil_"
# It is the user's macro directory



# Global Variables
# ------------------------------------------------------------------------------------------------

dialogIndex = [1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# These are the code numbers pertaining to the entire program's dialogs
# Each dialog box is assigned an initial code number.
# Each of the numbers given in the list from element 2 t0 11
# correspond to a dialog box as mentioned in the macro's
# main DocString above.
# The 1st element contains the current dialog box's index number
# Read the DocString of the '_setDialogIndex' method in the
# 'AeroFoilDialog' class to know more about its implementation.
doc = app.activeDocument()



# Main Function Class
# ------------------------------------------------------------------------------------------------

class AeroFoil:

    """
    The 'AeroFoil' class is the AeroFoil object itself. It is a non-interactive
    console-based class that is responsible for physical creation of the custom
    2D airfoil curves/shapes. The gathered user input data is used for the process.

    Functions include:
    __init__
    copy
    characterize
    create
    _create_tempX_var
    _createSketcherPolyLine
    _createSketcherBSpline
    """

    def __init__(self, obj):
        """
        This function initializes of the 'AeroFoil' class.
        This function transfers the user input data through the 'obj' variable.

        Arguments
        ----------
        obj: An instance of the 'AeroFoilDialog' object.
        """
        global UNITSCONVERSION
        self.profileName = generateName("AeroFoil")
        self.chord = obj.chordLength * UNITSCONVERSION[obj.chordUnits]
        # 'designtype' is used as a container for a set of relevant variables
        self.designtype = [obj.workbench, obj.curveType]
        self.designclosed = obj.closed_
        self.designsplit = obj.splitCurve
        self.designsplitmode = obj.splitCurveMode
        self.defaultEndPoints = obj.defaultEndPoints
        # 'midIndices' is used as a container for a set of relevant variables
        self.midIndices = [obj.midIndex1, obj.midIndex2]
        self.points = []
        self.points.append(obj.pointsX)
        self.points.append(obj.pointsY)
        self.n_units = len(self.points[0])
        self.designprogressbar = obj.progressBar_
        # 'objRefData' is used as a container for a set of relevant variables
        self.objRefData = [
            obj.airfoilType,
            obj.airfoil4DNumber,
            obj.airfoil5DNumber,
            obj.airfoilProfileType,
            obj.importFrom,
        ]

    def copy(self, quantity_):
        """
        This function creates multiple copies of the created airfoil curves/shapes.

        Arguments
        ----------
        quantity_: (Integer) Number of copies required.
        """
        if quantity_ != 1:
            refNum = int(re.findall(r"\d+", self.profileName)[0])
            gui.Selection.clearSelection()
            if self.designsplit:
                gui.Selection.addSelection(
                    doc.getObjectsByLabel(self.profileName + "_Upper")[0]
                )
                gui.Selection.addSelection(
                    doc.getObjectsByLabel(self.profileName + "_Lower")[0]
                )
            else:
                gui.Selection.addSelection(doc.getObjectsByLabel(self.profileName)[0])
            gui.runCommand("Std_Copy")
            for i in range(quantity_ - 1):
                gui.runCommand("Std_Paste")
                if self.designsplit:
                    doc.getObjectsByLabel(
                        "AeroFoil_" + str(refNum) + "_Upper" + str(i + 1).zfill(3)
                    )[0].Label = ("AeroFoil_" + str(refNum + i + 1) + "_Upper")
                    doc.getObjectsByLabel(
                        "AeroFoil_" + str(refNum) + "_Lower" + str(i + 1).zfill(3)
                    )[0].Label = ("AeroFoil_" + str(refNum + i + 1) + "_Lower")
                else:
                    doc.getObjectsByLabel("AeroFoil_" + str(refNum + i + 1).zfill(3))[
                        0
                    ].Label = "AeroFoil_" + str(refNum + i + 1)
                if self.designprogressbar.value() < 99:
                    self.designprogressbar.setValue(
                        round(75 + (((i + 1) / (4 * quantity_)) * 100))
                    )
        self.designprogressbar.setValue(100)
        time.sleep(1)

    def characterize(self):
        """
        This function adds external (read-only) properties to an instance of the AeroFoil object.
        The user input data has been obtained from the '__init__' module of this class.

        Properties
        ---------------
        Airfoil Type:         Options - NACA 4 Digit, NACA 5 Digit, Custom Curves (Symmetric or
                              Asymmetric), or Custom Points (DAT or CSV)
        Design Curve Type:    Options - Unsplit or Open Split or Open Split (End Points Fixed) or
                              Closed Split or Closed Split (End Points Fixed) |
                              Polygon or BSpline | Draft or Sketch or Surface
        Airfoil Chord Length: Length in millimetres (mm)
        Number of Points :    Number of airfoil points
        """
        try:
            objRef = doc.getObjectsByLabel(self.profileName)[0]
            objRef.addProperty("App::PropertyString", "AirfoilType", "", "", 1)
            objRef.addProperty("App::PropertyLength", "AirfoilChordLength", "", "", 1)
            objRef.addProperty("App::PropertyString", "DesignCurveType", "", "", 1)
            objRef.addProperty("App::PropertyInteger", "NumberOfPoints", "", "", 1)
            tempStr = ""
            # Refer to the '__init__' method of this class for more info. on 'objRefData'
            if self.objRefData[0] == 1:
                tempStr = "NACA - " + self.objRefData[1]
            elif self.objRefData[0] == 2:
                tempStr = "NACA - " + self.objRefData[2]
            elif self.objRefData[0] == 3 and self.objRefData[3] == 1:
                tempStr = "Custom Curves (Symmetric)"
            elif self.objRefData[0] == 3 and self.objRefData[3] == 2:
                tempStr = "Custom Curves (Asymmetric)"
            elif self.objRefData[0] == 4 and self.objRefData[4] == 1:
                tempStr = "Custom Points (DAT)"
            elif self.objRefData[0] == 4 and self.objRefData[4] == 2:
                tempStr = "Custom Points (CSV)"
            objRef.AirfoilType = tempStr
            objRef.AirfoilChordLength = str(self.chord) + "mm"
            tempStr = ""
            if self.designsplit:
                if self.designsplitmode == 1:
                    tempStr += "Open Split "
                else:
                    tempStr += "Closed Split "
                tempStr += "(End Points Fixed) " if self.defaultEndPoints else ""
            else:
                tempStr += "Unsplit "
            tempStr += "Polygon " if self.designtype[1] == 1 else "BSpline "
            if self.designclosed:
                tempStr += "Surface"
            elif self.designtype[0] == 1:
                tempStr += "Sketch"
            elif self.designtype[0] == 2:
                tempStr += "Draft"
            objRef.DesignCurveType = tempStr
            objRef.NumberOfPoints = self.n_units - 1
        except Exception:
            print(
                "\nCannot generate AeroFoil properties in FreeCAD version &#60;0.19 !\n"
            )
            app.Console.PrintWarning(
                "\nCannot generate AeroFoil properties in FreeCAD version &#60;0.19 !\n"
            )

    def create(self):
        """
        This function is responsible for physical creation of the custom 2D airfoil curves/shapes.
        The user input data has been obtained from the '__init__' module of this class.
        This function utilizes the 'try ... except' method to avoid any complications
        on the user's end. A simple error message is displayed instead.
        """
        # Generating Polygons and BSplines
        try:
            if self.designtype[0] == 2:
                if self.designtype[1] == 1:
                    if self.designsplit:
                        self._createSketcherPolyLine(
                            self.profileName + "_Upper", 0, self.midIndices[0]
                        )
                        self._createSketcherPolyLine(
                            self.profileName + "_Lower",
                            self.midIndices[1],
                            len(self.points[0]) - 1,
                        )
                    else:
                        self._createSketcherPolyLine(
                            self.profileName, 0, len(self.points[0]) - 1
                        )
                elif self.designtype[1] == 2:
                    if self.designsplit:
                        self._createSketcherBSpline(
                            self.profileName + "_Upper", 0, self.midIndices[0]
                        )
                        self._createSketcherBSpline(
                            self.profileName + "_Lower",
                            self.midIndices[1],
                            len(self.points[0]) - 1,
                        )
                    else:
                        self._createSketcherBSpline(
                            self.profileName, 0, len(self.points[0]) - 1
                        )
            elif self.designtype[0] == 1:
                tempXif, tempXm = 0, 0
                i_count, iteration = 0, 1
                if self.designsplit:
                    iteration = 2
                while i_count < iteration:
                    DWireOrBSpline_, pointsVector, draftCurveClosed = 0, [], True
                    startIndex, endIndex = 0, len(self.points[0]) - 1
                    draftOutputName = self.profileName
                    n_ = len(self.points[0])
                    if self.designsplit:
                        draftCurveClosed = False
                        startIndex, endIndex = (
                            (0, self.midIndices[0])
                            if i_count == 0
                            else (self.midIndices[1], len(self.points[0]) - 1)
                        )
                        tempXif, tempXm, startIndex, endIndex = self._create_tempX_var(startIndex, endIndex)
                        draftOutputName = (
                            self.profileName + "_Upper"
                            if i_count == 0
                            else self.profileName + "_Lower"
                        )
                        n_ = endIndex - startIndex + 1
                    if self.designsplit and (
                        tempXif != self.points[0][startIndex]
                        or self.points[1][startIndex] != 0
                    ):
                        pointsVector.append(app.Vector(tempXif, 0, 0))
                    for i in range(startIndex, endIndex + 1):
                        pointsVector.append(
                            app.Vector(self.points[0][i], 0, self.points[1][i])
                        )
                        if not self.designsplit:
                            if self.designprogressbar.value() < 75:
                                self.designprogressbar.setValue(
                                    round(50 + ((i / (4 * n_)) * 100))
                                )
                        elif self.designsplit and i_count == 0:
                            if self.designprogressbar.value() < 62.5:
                                self.designprogressbar.setValue(
                                    round(50 + ((i / (8 * n_)) * 100))
                                )
                        else:
                            if self.designprogressbar.value() < 75:
                                self.designprogressbar.setValue(
                                    round(62.5 + ((i / (8 * n_)) * 100))
                                )
                    if self.designsplit and (
                        tempXm != self.points[0][endIndex]
                        or self.points[1][endIndex] != 0
                    ):
                        pointsVector.append(app.Vector(tempXm, 0, 0))
                    if self.designtype[1] == 1:
                        # if self.designclosed is determined by face=self.designclosed
                        DWireOrBSpline_ = Draft.makeWire(
                            pointsVector,
                            closed=draftCurveClosed,
                            placement=None,
                            face=self.designclosed,
                            support=None,
                        )
                    elif self.designtype[1] == 2:
                        # if self.designclosed is determined by face=self.designclosed
                        DWireOrBSpline_ = Draft.makeBSpline(
                            pointsVector,
                            closed=draftCurveClosed,
                            placement=None,
                            face=self.designclosed,
                            support=None,
                        )
                        if self.designsplit and self.designsplitmode == 2:
                            pointsVector_aux = [pointsVector[0], pointsVector[-1]]
                            DWire_aux = Draft.makeWire(
                                pointsVector_aux,
                                closed=False,
                                placement=None,
                                face=False,
                                support=None,
                            )
                            addList, deleteList = Draft.upgrade(
                                [DWireOrBSpline_, DWire_aux], delete=True, force=None
                            )
                    doc.recompute()
                    if self.designsplit and self.designsplitmode == 2:
                        doc.getObject(addList[0].Name).Label = draftOutputName
                    else:
                        shape_ = doc.addObject("Part::Feature", draftOutputName)
                        shape_.Shape = DWireOrBSpline_.Shape
                        doc.removeObject(DWireOrBSpline_.Label)
                    i_count += 1
        except Exception:
            # Unexpected Error Occurred while Processing
            try:
                doc.removeObject(self.profileName)
                doc.removeObject(self.profileName + "_Upper")
                doc.removeObject(self.profileName + "_Lower")
            except Exception:
                pass
            doc.recompute()
            return False
        doc.recompute()
        gui.activeDocument().activeView().viewFront()
        gui.SendMsgToActiveView("ViewFit")
        return True

    def _create_tempX_var(self, startIndex, endIndex):
        """
        This function determines the start and end points of a 'split' curve.
        This function generates additional start and end points if
        their existing counterparts do not have a Y-axis value of zero (0).
        This function calls the linear interpolation method to achieve the same.

        Arguments
        ----------
        startIndex: (Integer) Zero-based index of the data points list to begin from.
        endIndex:   (Integer) Zero-based index of the data points list to end to.
        """
        posVar, negVar, startIndex_new, endIndex_new = 0, 0, startIndex, endIndex
        for i1 in range(startIndex, startIndex + int(0.1 * (endIndex - startIndex))):
            if self.points[1][i1] >= 0:
                posVar += 1
            else:
                negVar += 1
        for j1 in range(startIndex, startIndex + int(0.1 * (endIndex - startIndex))):
            if posVar >= negVar:
                if self.points[1][j1] >= 0:
                    startIndex_new = j1
                    break
            else:
                if self.points[1][j1] < 0:
                    startIndex_new = j1
                    break
        for i2 in range(endIndex, endIndex - int(0.1 * (endIndex - startIndex)), -1):
            if self.points[1][i2] >= 0:
                posVar += 1
            else:
                negVar += 1
        for j2 in range(endIndex, endIndex - int(0.1 * (endIndex - startIndex)), -1):
            if posVar >= negVar:
                if self.points[1][j2] >= 0:
                    endIndex_new = j2
                    break
            else:
                if self.points[1][j2] < 0:
                    endIndex_new = j2
                    break
        if self.defaultEndPoints:
            tempXif = round(self.points[0][startIndex_new], 2)
            tempXm = round(self.points[0][endIndex_new], 2)
            self.points[0][startIndex_new] = round(self.points[0][startIndex_new], 2)
            self.points[0][endIndex_new] = round(self.points[0][endIndex_new], 2)
        else:
            if startIndex_new == 0:
                xi_, yi_ = self.points[0][0], self.points[1][0]
                xf_, yf_ = (
                    (self.points[0][-1], self.points[1][-1])
                    if (
                        self.points[0][0] != self.points[0][-1]
                        or self.points[1][0] != self.points[1][-1]
                    )
                    else (self.points[0][-2], self.points[1][-2])
                )
                x1m_, y1m_ = self.points[0][endIndex_new], self.points[1][endIndex_new]
                x2m_, y2m_ = (
                    (self.points[0][endIndex_new + 1], self.points[1][endIndex_new + 1])
                    if self.points[0][endIndex_new] != self.points[0][endIndex_new + 1]
                    or self.points[1][endIndex_new] != self.points[1][endIndex_new + 1]
                    else (self.points[0][endIndex_new + 2], self.points[1][endIndex_new + 2])
                )
            else:
                xi_, yi_ = self.points[0][startIndex_new], self.points[1][startIndex_new]
                xf_, yf_ = (
                    (self.points[0][startIndex_new - 1], self.points[1][startIndex_new - 1])
                    if (
                        self.points[0][startIndex_new] != self.points[0][startIndex_new - 1]
                        or self.points[1][startIndex_new] != self.points[1][startIndex_new - 1]
                    )
                    else (
                        self.points[0][startIndex_new - 2],
                        self.points[1][startIndex_new - 2],
                    )
                )
                x1m_, y1m_ = self.points[0][-1], self.points[1][-1]
                x2m_, y2m_ = (
                    (self.points[0][0], self.points[1][0])
                    if self.points[0][-1] != self.points[0][0]
                    or self.points[1][-1] != self.points[1][0]
                    else (self.points[0][1], self.points[1][1])
                )
            tempXif = interpolateNum(yi_, xi_, yf_, xf_, 0)
            tempXm = interpolateNum(y1m_, x1m_, y2m_, x2m_, 0)
        return tempXif, tempXm, startIndex_new, endIndex_new

    def _createSketcherPolyLine(self, sketchName, startIndex, endIndex):
        """
        This function creates the Sketcher Workbench based PolyLine curve.

        Arguments
        ----------
        sketchName: (String)  The name/label of the generated sketch.
        startIndex: (Integer) Zero-based index of the data points list to begin from.
        endIndex:   (Integer) Zero-based index of the data points list to end to.
        """
        # Sketch Preparation and Naming
        sketchObj = doc.addObject("Sketcher::SketchObject", sketchName)
        sketchObj.Placement = app.Placement(
            app.Vector(0.000000, 0.000000, 0.000000),
            app.Rotation(-0.707107, 0.000000, 0.000000, -0.707107),
        )
        sketchObj.MapMode = "Deactivated"
        # Sketch PolyLine Procedure
        count, tempBool = 0, False
        tempXif, tempXm = 0, 0
        if self.designsplit:
            tempXif, tempXm, startIndex, endIndex = self._create_tempX_var(startIndex, endIndex)
            if (
                tempXif == self.points[0][startIndex]
                and self.points[1][startIndex] == 0
            ):
                tempBool = False
            else:
                tempBool = True
                sketchObj.addGeometry(
                    Part.LineSegment(
                        app.Vector(tempXif, 0, 0),
                        app.Vector(
                            self.points[0][startIndex], self.points[1][startIndex], 0
                        ),
                    ),
                    False,
                )
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint("DistanceX", 0, 1, tempXif)
                )
                sketchObj.setDatum(
                    constraintIndex, app.Units.Quantity(str(tempXif) + "mm")
                )
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint("DistanceY", 0, 1, 0)
                )
                sketchObj.setDatum(constraintIndex, app.Units.Quantity(str(0) + "mm"))
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint("DistanceX", 0, 2, self.points[0][startIndex])
                )
                sketchObj.setDatum(
                    constraintIndex,
                    app.Units.Quantity(str(self.points[0][startIndex]) + "mm"),
                )
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint("DistanceY", 0, 2, self.points[1][startIndex])
                )
                sketchObj.setDatum(
                    constraintIndex,
                    app.Units.Quantity(str(self.points[1][startIndex]) + "mm"),
                )
        sketchObj.addGeometry(
            Part.LineSegment(
                app.Vector(self.points[0][startIndex], self.points[1][startIndex], 0),
                app.Vector(
                    self.points[0][startIndex + 1], self.points[1][startIndex + 1], 0
                ),
            ),
            False,
        )
        if tempBool:
            sketchObj.addConstraint(Sketcher.Constraint("Coincident", 0, 2, 1, 1))
            count = 2
        else:
            count = 1
        n_ = endIndex - startIndex + 1
        for i in range(startIndex + 1, endIndex):
            sketchObj.addGeometry(
                Part.LineSegment(
                    app.Vector(self.points[0][i], self.points[1][i], 0),
                    app.Vector(self.points[0][i + 1], self.points[1][i + 1], 0),
                ),
                False,
            )
            sketchObj.addConstraint(
                Sketcher.Constraint("Coincident", count - 1, 2, count, 1)
            )
            if self.designprogressbar.value() < 62.5:
                self.designprogressbar.setValue(round(50 + ((count / (8 * n_)) * 100)))
            count += 1
        tempVar1, tempVar2 = self.points[0][endIndex], self.points[1][endIndex]
        if self.designsplit and (
            tempXm != self.points[0][endIndex] or self.points[1][endIndex] != 0
        ):
            sketchObj.addGeometry(
                Part.LineSegment(
                    app.Vector(self.points[0][endIndex], self.points[1][endIndex], 0),
                    app.Vector(tempXm, 0, 0),
                ),
                False,
            )
            sketchObj.addConstraint(
                Sketcher.Constraint("Coincident", count - 1, 2, count, 1)
            )
            tempVar1, tempVar2 = tempXm, 0
            count += 1
        if self.designsplitmode == 2:
            sketchObj.addGeometry(
                Part.LineSegment(
                    app.Vector(tempVar1, tempVar2, 0),
                    app.Vector(
                        self.points[0][startIndex], self.points[1][startIndex], 0
                    ),
                ),
                False,
            )
            sketchObj.addConstraint(
                Sketcher.Constraint("Coincident", count - 1, 2, count, 1)
            )
            sketchObj.addConstraint(Sketcher.Constraint("Coincident", count, 2, 0, 1))
        if self.designsplit:
            # Here, 'count; denotes the sketcher line number
            count = 1 if tempBool else 0
        else:
            sketchObj.addConstraint(
                Sketcher.Constraint("Coincident", count - 1, 2, 0, 1)
            )
            count = 0
        for j in range(startIndex, endIndex - 1):
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", count, 2, self.points[0][j + 1])
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(self.points[0][j + 1]) + "mm")
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", count, 2, self.points[1][j + 1])
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(self.points[1][j + 1]) + "mm")
            )
            if self.designprogressbar.value() < 75:
                self.designprogressbar.setValue(
                    round(62.5 + ((count / (8 * n_)) * 100))
                )
            count += 1
        if self.designsplit:
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", count, 2, self.points[0][endIndex])
            )
            sketchObj.setDatum(
                constraintIndex,
                app.Units.Quantity(str(self.points[0][endIndex]) + "mm"),
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", count, 2, self.points[1][endIndex])
            )
            sketchObj.setDatum(
                constraintIndex,
                app.Units.Quantity(str(self.points[1][endIndex]) + "mm"),
            )
            count += 1
            if tempXm != self.points[0][endIndex] or self.points[1][endIndex] != 0:
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint("DistanceX", count, 2, tempXm)
                )
                sketchObj.setDatum(
                    constraintIndex, app.Units.Quantity(str(tempXm) + "mm")
                )
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint("DistanceY", count, 2, 0)
                )
                sketchObj.setDatum(constraintIndex, app.Units.Quantity(str(0) + "mm"))
                count += 1
            if not tempBool and self.designsplitmode == 2:
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint(
                        "DistanceX", count, 2, self.points[0][startIndex]
                    )
                )
                sketchObj.setDatum(
                    constraintIndex,
                    app.Units.Quantity(str(self.points[0][startIndex]) + "mm"),
                )
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint(
                        "DistanceY", count, 2, self.points[1][startIndex]
                    )
                )
                sketchObj.setDatum(
                    constraintIndex,
                    app.Units.Quantity(str(self.points[1][startIndex]) + "mm"),
                )
                count += 1
        if not tempBool and self.designsplitmode != 2:
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", 0, 1, self.points[0][startIndex])
            )
            sketchObj.setDatum(
                constraintIndex,
                app.Units.Quantity(str(self.points[0][startIndex]) + "mm"),
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", 0, 1, self.points[1][startIndex])
            )
            sketchObj.setDatum(
                constraintIndex,
                app.Units.Quantity(str(self.points[1][startIndex]) + "mm"),
            )

    def _createSketcherBSpline(self, sketchName, startIndex, endIndex):
        """
        This function creates the Sketcher Workbench based BSpline curve.

        Arguments
        ----------
        sketchName: (String)  The name/label of the generated sketch.
        startIndex: (Integer) Zero-based index of the data points list to begin from.
        endIndex:   (Integer) Zero-based index of the data points list to end to.
        """
        # Sketch Preparation and Naming
        sketchObj = doc.addObject("Sketcher::SketchObject", sketchName)
        sketchObj.Placement = app.Placement(
            app.Vector(0.000000, 0.000000, 0.000000),
            app.Rotation(-0.707107, 0.000000, 0.000000, -0.707107),
        )
        sketchObj.MapMode = "Deactivated"
        # Sketch BSpline Procedure
        count, points, conList = 0, [], []
        n_ = endIndex - startIndex + 1
        isXif, isXm = False, False
        tempXif, tempXm = 0, 0
        if self.designsplit:
            tempXif, tempXm, startIndex, endIndex = self._create_tempX_var(startIndex, endIndex)
        if self.designsplit and (
            tempXif != self.points[0][startIndex] or self.points[1][startIndex] != 0
        ):
            sketchObj.addGeometry(
                Part.Circle(app.Vector(tempXif, 0, 0), app.Vector(0, 0, 1), 10), True
            )
            sketchObj.addGeometry(
                Part.Circle(
                    app.Vector(
                        self.points[0][startIndex], self.points[1][startIndex], 0
                    ),
                    app.Vector(0, 0, 1),
                    10,
                ),
                True,
            )
            sketchObj.addConstraint(Sketcher.Constraint("Radius", 0, 1.000000))
            sketchObj.addConstraint(Sketcher.Constraint("Equal", 0, 1))
            sketchObj.addGeometry(
                Part.Circle(
                    app.Vector(
                        self.points[0][startIndex + 1],
                        self.points[1][startIndex + 1],
                        0,
                    ),
                    app.Vector(0, 0, 1),
                    10,
                ),
                True,
            )
            sketchObj.addConstraint(Sketcher.Constraint("Equal", 0, 2))
            isXif = True
            count = 3
        else:
            sketchObj.addGeometry(
                Part.Circle(
                    app.Vector(
                        self.points[0][startIndex], self.points[1][startIndex], 0
                    ),
                    app.Vector(0, 0, 1),
                    10,
                ),
                True,
            )
            sketchObj.addGeometry(
                Part.Circle(
                    app.Vector(
                        self.points[0][startIndex + 1],
                        self.points[1][startIndex + 1],
                        0,
                    ),
                    app.Vector(0, 0, 1),
                    10,
                ),
                True,
            )
            sketchObj.addConstraint(Sketcher.Constraint("Radius", 0, 1.000000))
            sketchObj.addConstraint(Sketcher.Constraint("Equal", 0, 1))
            count = 2
        for h in range(startIndex + 2, endIndex + 1):
            sketchObj.addGeometry(
                Part.Circle(
                    app.Vector(self.points[0][h], self.points[1][h], 0),
                    app.Vector(0, 0, 1),
                    10,
                ),
                True,
            )
            sketchObj.addConstraint(Sketcher.Constraint("Equal", 0, count))
            if self.designprogressbar.value() < 60:
                self.designprogressbar.setValue(round(50 + ((h / (10 * n_)) * 100)))
            count += 1
        if self.designsplit and (
            tempXm != self.points[0][endIndex] or self.points[1][endIndex] != 0
        ):
            sketchObj.addGeometry(
                Part.Circle(app.Vector(tempXm, 0, 0), app.Vector(0, 0, 1), 10), True
            )
            sketchObj.addConstraint(Sketcher.Constraint("Equal", 0, count))
            isXm = True
            count += 1
        tempVal = count
        if isXif:
            points.append(app.Vector(tempXif, 0))
            conList.append(
                Sketcher.Constraint(
                    "InternalAlignment:Sketcher::BSplineControlPoint", 0, 3, tempVal, 0
                )
            )
        count = 0 + isXif
        for i in range(startIndex, endIndex + 1):
            points.append(app.Vector(self.points[0][i], self.points[1][i]))
            conList.append(
                Sketcher.Constraint(
                    "InternalAlignment:Sketcher::BSplineControlPoint",
                    count,
                    3,
                    tempVal,
                    count,
                )
            )
            if self.designprogressbar.value() < 70:
                self.designprogressbar.setValue(round(60 + ((i / (10 * n_)) * 100)))
            count += 1
        if isXm:
            points.append(app.Vector(tempXm, 0))
            conList.append(
                Sketcher.Constraint(
                    "InternalAlignment:Sketcher::BSplineControlPoint",
                    count,
                    3,
                    tempVal,
                    count,
                )
            )
            count += 1
        if self.designsplit:
            sketchObj.addGeometry(
                Part.BSplineCurve(points, None, None, False, 3, None, False), False
            )
        else:
            sketchObj.addGeometry(
                Part.BSplineCurve(points, None, None, True, 3, None, False), False
            )
        sketchObj.addConstraint(conList)
        sketchObj.exposeInternalGeometry(tempVal)
        tempVar1x = tempXif if isXif else self.points[0][startIndex]
        tempVar1y = 0 if isXif else self.points[1][startIndex]
        tempVar1bx = (
            self.points[0][startIndex] if isXif else self.points[0][startIndex + 1]
        )
        tempVar1by = (
            self.points[1][startIndex] if isXif else self.points[1][startIndex + 1]
        )
        tempVar2x = tempXm if isXm else self.points[0][endIndex]
        tempVar2y = 0 if isXm else self.points[1][endIndex]
        count, startFrom = 0, 0
        if isXif:
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", -1, 1, tempVal, 1, tempVar1x)
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(tempVar1x) + "mm")
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", -1, 1, tempVal, 1, tempVar1y)
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(tempVar1y) + "mm")
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", -1, 1, count + 1, 3, tempVar1bx)
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(tempVar1bx) + "mm")
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", -1, 1, count + 1, 3, tempVar1by)
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(tempVar1by) + "mm")
            )
            startFrom = startIndex + 1
            count += 2
        else:
            startFrom = startIndex
        if self.designsplit:
            endTo = endIndex
            if not isXif:
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint(
                        "DistanceX", -1, 1, tempVal, 1, self.points[0][startIndex]
                    )
                )
                sketchObj.setDatum(
                    constraintIndex,
                    app.Units.Quantity(str(self.points[0][startIndex]) + "mm"),
                )
                constraintIndex = sketchObj.addConstraint(
                    Sketcher.Constraint(
                        "DistanceY", -1, 1, tempVal, 1, self.points[1][startIndex]
                    )
                )
                sketchObj.setDatum(
                    constraintIndex,
                    app.Units.Quantity(str(self.points[1][startIndex]) + "mm"),
                )
                startFrom = startIndex + 1
                count += 1
        else:
            endTo = endIndex + 1
        for j in range(startFrom, endTo):
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", -1, 1, count, 3, self.points[0][j])
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(self.points[0][j]) + "mm")
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", -1, 1, count, 3, self.points[1][j])
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(self.points[1][j]) + "mm")
            )
            if self.designprogressbar.value() < 75:
                self.designprogressbar.setValue(round(70 + ((j / (20 * n_)) * 100)))
            count += 1
        if self.designsplit:
            tempVar1, tempVar2 = 0, 0
            if isXm:
                tempVar1, tempVar2 = count, 3
            else:
                tempVar1, tempVar2 = tempVal, 2
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint(
                    "DistanceX", -1, 1, tempVar1, tempVar2, self.points[0][endIndex]
                )
            )
            sketchObj.setDatum(
                constraintIndex,
                app.Units.Quantity(str(self.points[0][endIndex]) + "mm"),
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint(
                    "DistanceY", -1, 1, tempVar1, tempVar2, self.points[1][endIndex]
                )
            )
            sketchObj.setDatum(
                constraintIndex,
                app.Units.Quantity(str(self.points[1][endIndex]) + "mm"),
            )
            count += 1
        if isXm:
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceX", -1, 1, tempVal, 2, tempVar2x)
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(tempVar2x) + "mm")
            )
            constraintIndex = sketchObj.addConstraint(
                Sketcher.Constraint("DistanceY", -1, 1, tempVal, 2, tempVar2y)
            )
            sketchObj.setDatum(
                constraintIndex, app.Units.Quantity(str(tempVar2y) + "mm")
            )
        if self.designsplitmode == 2:
            sketchObj.addGeometry(
                Part.LineSegment(
                    app.Vector(tempVar1x, tempVar1y, 0),
                    app.Vector(tempVar2x, tempVar2y, 0),
                ),
                False,
            )
            sketchObj.addConstraint(
                Sketcher.Constraint("Coincident", (tempVal * 2) - 1, 2, tempVal, 1)
            )
            sketchObj.addConstraint(
                Sketcher.Constraint("Coincident", (tempVal * 2) - 1, 1, tempVal, 2)
            )



# Sub-main Function Class
# ------------------------------------------------------------------------------------------------

class AeroFoilDialog:

    """
    The 'AeroFoilDialog' class itself is the AeroFoil GUI interface.
    It contains dialog boxes that go to and fro, from the initial input dialog box
    to the final creation dialog box. This class accumulates the user's inputs on
    how the airfoils are to be created: their dimensions, their design type,
    their resolution, their multiplicity, etc.

    This class is also responsible for validating the input choices and values,
    and notifying or warning the user accordingly.

    Functions include:
    __init__
    _d
    _createDialogs
    _close
    _next
    _okay
    _loadFile
    _create
    _af_d2c_radio_toggled
    _af_d3_spinbox_1_toggled
    _af_d3_spinbox_2_toggled
    _af_d3_checkbox_1_toggled
    _af_d3_checkbox_2_toggled
    _af_d3_checkbox_5_toggled
    _af_d3_checkbox_3_toggled
    _af_d3_checkbox_4_toggled
    _af_d3_radio_toggled
    _functionsList
    """

    def __init__(self):
        """
        This function initializes of the 'AeroFoilDialog' class.
        """
        # Variables Pertaining to the Entire Program
        (
            self.canMirror,
            self.functionElements,
            self.functionElements_Pos,
            self.pointsX,
            self.pointsY,
        ) = (True, [], [], [], [])
        self.tempStart, self.tempEnd = 0, 0
        self.midIndex1, self.midIndex2 = 0, 0
        # Variables Pertaining to AeroFoil_Initial_Dialog
        self.airfoilType = 1
        # Variables Pertaining to AeroFoil_NACA4Digit_Dialog
        self.airfoil4DNumber = ""
        # Variables Pertaining to AeroFoil_NACA5Digit_Dialog
        self.airfoil5DNumber = ""
        # Variables Pertaining to AeroFoil_CurvesInput_Dialog
        self.airfoilProfileType, self.topCurveFunction, self.bottomCurveFunction = (
            1,
            "",
            "",
        )
        # Variables Pertaining to AeroFoil_PointsInput_Dialog
        self.importFrom, self.mirroring = 1, False
        # Variables Pertaining to AeroFoil_DATInput_Dialog
        self.lineStart, self.lineEnd, self.decimalType = 0, 0, 1
        # Variables Pertaining to AeroFoil_CSVInput_Dialog
        self.col1, self.col2, self.row1, self.row2 = 1, 2, 0, 0
        # Variables Pertaining to AeroFoil_FileLoad_Dialog
        (
            self.loadSuccess,
            self.loadedFilePath,
            self.loadedFile,
            self.loadedFileContents,
        ) = (False, [""], "", [])
        # Variables Pertaining to AeroFoil_Final_Dialog
        (
            self.refine,
            self.refineParam,
            self.multi,
            self.multiParam,
            self.closed_,
            self.workbench,
            self.curveType,
            self.maxRefineParamWarned,
            self.maxQuantityParamWarned,
            self.chordLength,
            self.chordUnits,
            self.progressBar_,
            self.splitCurve,
            self.splitCurveMode,
            self.defaultEndPoints,
        ) = (False, 2, False, 2, False, 1, 1, False, False, 0, 1, 0, False, 1, False)
        # Actual Functions begin here
        dialogIndex[0] = 1
        self._createDialogs()

    def _d(self, qcode, objStr):
        """
        This function is a shortcut for obtaining a dialog's UI element.

        Arguments
        ----------
        qcode: A distinct code for each UI element as listed below.
        objStr: The UI element's name/label.
        """
        qkey = [
            0,
            QPushButton,
            QLineEdit,
            QComboBox,
            QRadioButton,
            QCheckBox,
            QSpinBox,
            QDoubleSpinBox,
            QLabel,
            QProgressBar,
        ]
        # Elements 2 to 10 are the various UI elements employed in this macro.
        # Ignore the 1st element; it's superfluous.
        return self.dialog.findChild(qkey[qcode], objStr)

    def _createDialogs(self):
        """
        This function generates and displays the AeroFoil GUI interface, that is,
        it creates all the dialog boxes for user interaction and input.
        """
        global MACRO_DIR
        global dialogIndex
        if dialogIndex[0] == 1:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "Initial_Dialog.ui")
            self._d(1, "af_d1_close_button").clicked.connect(lambda: self._close())
            self._d(1, "af_d1_next_button").clicked.connect(lambda: self._next(1))
            self._d(3, "af_d1_combo").setCurrentIndex(self.airfoilType - 1)
        elif dialogIndex[0] == 2:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "NACA4Digit_Dialog.ui")
            self._d(1, "af_d2a_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2a_back_button").clicked.connect(lambda: self._next(-1))
            self._d(2, "af_d2a_textbox").setText(self.airfoil4DNumber)
        elif dialogIndex[0] == 3:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "NACA5Digit_Dialog.ui")
            self._d(1, "af_d2b_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2b_back_button").clicked.connect(lambda: self._next(-1))
            self._d(2, "af_d2b_textbox").setText(self.airfoil5DNumber)
        elif dialogIndex[0] == 4:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "CurvesInput_Dialog.ui")
            self._d(2, "af_d2c_textbox_1").setText(self.topCurveFunction)
            self._d(2, "af_d2c_textbox_2").setText(self.bottomCurveFunction)
            self._d(4, "af_d2c_radio_1").toggled.connect(
                lambda: self._af_d2c_radio_toggled()
            )
            if self.airfoilProfileType == 1:
                self._d(4, "af_d2c_radio_1").setChecked(True)
            else:
                self._d(4, "af_d2c_radio_2").setChecked(True)
            self._d(1, "af_d2c_list_button").clicked.connect(
                lambda: self._functionsList()
            )
            self._d(1, "af_d2c_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2c_back_button").clicked.connect(lambda: self._next(-1))
        elif dialogIndex[0] == 5:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "PointsInput_Dialog.ui")
            if self.importFrom == 1:
                self._d(4, "af_d2d_radio_1").setChecked(True)
            else:
                self._d(4, "af_d2d_radio_2").setChecked(True)
            if self.mirroring:
                self._d(5, "af_d2d_checkbox").setChecked(True)
            else:
                self._d(5, "af_d2d_checkbox").setChecked(False)
            self._d(1, "af_d2d_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2d_back_button").clicked.connect(lambda: self._next(-1))
        elif dialogIndex[0] == 6:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "DATInput_Dialog.ui")
            self._d(6, "af_d2d1a_spinBox_1").setValue(self.tempStart)
            self._d(6, "af_d2d1a_spinBox_2").setValue(self.tempEnd)
            if self.decimalType == 1:
                self._d(4, "af_d2d1a_radio_1").setChecked(True)
            else:
                self._d(4, "af_d2d1a_radio_2").setChecked(True)
            self._d(1, "af_d2d1a_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2d1a_back_button").clicked.connect(lambda: self._next(-1))
        elif dialogIndex[0] == 7:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "CSVInput_Dialog.ui")
            self._d(6, "af_d2d1b_spinBox_1").setValue(self.col1)
            self._d(6, "af_d2d1b_spinBox_2").setValue(self.col2)
            self._d(6, "af_d2d1b_spinBox_3").setValue(self.tempStart)
            self._d(6, "af_d2d1b_spinBox_4").setValue(self.tempEnd)
            if self.decimalType == 1:
                self._d(4, "af_d2d1b_radio_1").setChecked(True)
            else:
                self._d(4, "af_d2d1b_radio_2").setChecked(True)
            self._d(1, "af_d2d1b_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2d1b_back_button").clicked.connect(lambda: self._next(-1))
        elif dialogIndex[0] == 8:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "FileLoad_Dialog.ui")
            self._d(2, "af_d2cd2_textbox").setText(self.loadedFilePath[0])
            if self.loadedFilePath[0] == "":
                self.loadSuccess = False
                self._d(8, "af_d2cd2_label_2").setText("File Not Loaded")
                self._d(8, "af_d2cd2_label_2").setStyleSheet("color: black;")
            else:
                if self.loadSuccess:
                    self._d(8, "af_d2cd2_label_2").setText("File Loaded Successfully")
                    self._d(8, "af_d2cd2_label_2").setStyleSheet("color: darkgreen;")
                else:
                    self._d(8, "af_d2cd2_label_2").setText(
                        "File Loaded Un-successfully"
                    )
                    self._d(8, "af_d2cd2_label_2").setStyleSheet("color: crimson;")
            self._d(1, "af_d2cd2_load_button").clicked.connect(lambda: self._loadFile())
            self._d(1, "af_d2cd2_next_button").clicked.connect(lambda: self._next(1))
            self._d(1, "af_d2cd2_back_button").clicked.connect(lambda: self._next(-1))
        elif dialogIndex[0] == 9:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "Final_Dialog.ui")
            if self.refine:
                self._d(6, "af_d3_spinbox_1").setValue(self.refineParam)
                self._d(6, "af_d3_spinbox_1").setEnabled(True)
                self._d(5, "af_d3_checkbox_1").setChecked(True)
            else:
                self.refineParam = 2
                self._d(6, "af_d3_spinbox_1").setValue(2)
                self._d(6, "af_d3_spinbox_1").setEnabled(False)
                self._d(5, "af_d3_checkbox_1").setChecked(False)
            if self.multi:
                self._d(6, "af_d3_spinbox_2").setValue(self.multiParam)
                self._d(6, "af_d3_spinbox_2").setEnabled(True)
                self._d(5, "af_d3_checkbox_2").setChecked(True)
            else:
                self.multiParam = 2
                self._d(6, "af_d3_spinbox_2").setValue(2)
                self._d(6, "af_d3_spinbox_2").setEnabled(False)
                self._d(5, "af_d3_checkbox_2").setChecked(False)
            if self.splitCurve:
                self._d(5, "af_d3_checkbox_5").setChecked(False)
                self._d(5, "af_d3_checkbox_5").setEnabled(False)
                self._d(5, "af_d3_checkbox_6").setChecked(False)
                self._d(5, "af_d3_checkbox_6").setEnabled(True)
                if self.splitCurveMode == 1:
                    self._d(5, "af_d3_checkbox_3").setChecked(True)
                    self._d(5, "af_d3_checkbox_4").setChecked(False)
                else:
                    self._d(5, "af_d3_checkbox_3").setChecked(False)
                    self._d(5, "af_d3_checkbox_4").setChecked(True)
                self._af_d3_checkbox_5_toggled()
            else:
                self._d(5, "af_d3_checkbox_3").setChecked(False)
                self._d(5, "af_d3_checkbox_4").setChecked(False)
                self._d(5, "af_d3_checkbox_6").setChecked(False)
                self._d(5, "af_d3_checkbox_6").setEnabled(False)
                self._d(5, "af_d3_checkbox_5").setChecked(False)
                self._d(5, "af_d3_checkbox_5").setEnabled(True)
                if self.closed_:
                    self._d(5, "af_d3_checkbox_3").setEnabled(False)
                    self._d(5, "af_d3_checkbox_4").setEnabled(False)
                    self._d(5, "af_d3_checkbox_5").setChecked(True)
                    self._af_d3_checkbox_5_toggled()
                else:
                    self._d(5, "af_d3_checkbox_5").setChecked(False)
                    self._d(4, "af_d3_radio_1").setEnabled(True)
                    self._d(4, "af_d3_radio_2").setEnabled(True)
                    if self.workbench == 1:
                        self._d(4, "af_d3_radio_1").setChecked(True)
                        self._d(4, "af_d3_radio_1a").setEnabled(True)
                        self._d(4, "af_d3_radio_1b").setEnabled(True)
                        self._d(4, "af_d3_radio_2a").setEnabled(False)
                        self._d(4, "af_d3_radio_2b").setEnabled(False)
                        if self.curveType == 1:
                            self._d(4, "af_d3_radio_1a").setChecked(True)
                        else:
                            self._d(4, "af_d3_radio_1b").setChecked(True)
                    else:
                        self._d(4, "af_d3_radio_2").setChecked(True)
                        self._d(4, "af_d3_radio_1a").setEnabled(False)
                        self._d(4, "af_d3_radio_1b").setEnabled(False)
                        self._d(4, "af_d3_radio_2a").setEnabled(True)
                        self._d(4, "af_d3_radio_2b").setEnabled(True)
                        if self.curveType == 1:
                            self._d(4, "af_d3_radio_2a").setChecked(True)
                        else:
                            self._d(4, "af_d3_radio_2b").setChecked(True)
            self.progressBar_ = self._d(9, "af_d3_progressbar")
            self.progressBar_.setEnabled(False)
            self.progressBar_.setValue(0)
            self._d(7, "af_d3_spinbox_3").setValue(self.chordLength)
            self._d(3, "af_d3_combobox").setCurrentIndex(self.chordUnits - 1)
            self._d(4, "af_d3_radio_1").toggled.connect(
                lambda: self._af_d3_radio_toggled()
            )
            self._d(5, "af_d3_checkbox_1").toggled.connect(
                lambda: self._af_d3_checkbox_1_toggled()
            )
            self._d(5, "af_d3_checkbox_2").toggled.connect(
                lambda: self._af_d3_checkbox_2_toggled()
            )
            self._d(5, "af_d3_checkbox_5").toggled.connect(
                lambda: self._af_d3_checkbox_5_toggled()
            )
            self._d(5, "af_d3_checkbox_3").clicked.connect(
                lambda: self._af_d3_checkbox_3_toggled()
            )
            self._d(5, "af_d3_checkbox_4").clicked.connect(
                lambda: self._af_d3_checkbox_4_toggled()
            )
            self._d(6, "af_d3_spinbox_1").valueChanged.connect(
                lambda: self._af_d3_spinbox_1_toggled()
            )
            self._d(6, "af_d3_spinbox_2").valueChanged.connect(
                lambda: self._af_d3_spinbox_2_toggled()
            )
            self._d(1, "af_d3_create_button").clicked.connect(
                lambda: self._startCreating()
            )
            self._d(1, "af_d3_close_button").clicked.connect(lambda: self._close())
            self._d(1, "af_d3_back_button").clicked.connect(lambda: self._next(-1))
        elif dialogIndex[0] == 10:
            self.dialog = gui.PySideUic.loadUi(MACRO_DIR + "Math_Functions_Box.ui")
            self._d(8, "af_mfb_label_6").setText(
                "<img src=" + MACRO_DIR + "mfb_img.gif>"
            )
            self._d(1, "af_mfb_okay_button").clicked.connect(lambda: self._okay())
        self.dialog.setWindowIcon(
            QtGui.QIcon(app.getUserMacroDir(True) + "/AeroFoil_UI_Files/AeroFoil.svg")
        )
        self.dialog.exec_()

# Button Functions
# ----------------------------------------------------------------

    def _close(self):
        """
        This function closes an open dialog box.
        This function is called when the 'Close' button is clicked.
        """
        self.dialog.done(1)

    def _next(self, direction):
        """
        This function takes the user from one dialog box to another.
        This function is called when the 'Next' or 'Back' buttons are clicked.

        Arguments
        ----------
        direction: '1' denotes a 'Go Next'; and '-1' denotes a 'Go Back'
        """
        global dialogIndex
        global MIN_DATA_POINTS
        if direction == -1:
            if dialogIndex[0] == 2:
                self.airfoil4DNumber = ""
            elif dialogIndex[0] == 3:
                self.airfoil5DNumber = ""
            elif dialogIndex[0] == 4:
                (
                    self.airfoilProfileType,
                    self.topCurveFunction,
                    self.bottomCurveFunction,
                ) = (1, "", "")
            elif dialogIndex[0] == 5:
                self.importFrom, self.mirroring = 1, False
            elif dialogIndex[0] == 6:
                self.lineStart, self.lineEnd, self.decimalType = 0, 0, 1
                self.tempStart, self.tempEnd, = (
                    0,
                    0,
                )
                self.midIndex1, self.midIndex2 = 0, 0
            elif dialogIndex[0] == 7:
                self.col1, self.col2, self.row1, self.row2 = 1, 2, 0, 0
                self.tempStart, self.tempEnd, = (
                    0,
                    0,
                )
                self.midIndex1, self.midIndex2 = 0, 0
            elif dialogIndex[0] == 8:
                (
                    self.loadedFilePath,
                    self.loadSuccess,
                    self.loadedFile,
                    self.loadedFileContents,
                ) = ([""], False, "", [])
            elif dialogIndex[0] == 9:
                (
                    self.refine,
                    self.refineParam,
                    self.multi,
                    self.multiParam,
                    self.closed_,
                    self.workbench,
                    self.curveType,
                    self.maxRefineParamWarned,
                    self.maxQuantityParamWarned,
                    self.chordLength,
                    self.chordUnits,
                    self.splitCurve,
                    self.splitCurveMode,
                    self.defaultEndPoints,
                ) = (
                    False,
                    2,
                    False,
                    2,
                    False,
                    1,
                    1,
                    False,
                    False,
                    0,
                    1,
                    False,
                    1,
                    False,
                )
            dialogIndex[0] = dialogIndex[dialogIndex[0]]
        else:
            if dialogIndex[0] == 1:
                self.airfoilType = self._d(3, "af_d1_combo").currentIndex() + 1
                if self.airfoilType == 1:
                    _setDialogIndex(2)
                elif self.airfoilType == 2:
                    _setDialogIndex(3)
                elif self.airfoilType == 3:
                    _setDialogIndex(4)
                elif self.airfoilType == 4:
                    _setDialogIndex(5)
            elif dialogIndex[0] == 2:
                self.airfoil4DNumber = self._d(2, "af_d2a_textbox").text()
                if _validateAirfoilNumber(self, 4):
                    _setDialogIndex(9)
                else:
                    return
            elif dialogIndex[0] == 3:
                self.airfoil5DNumber = self._d(2, "af_d2b_textbox").text()
                if _validateAirfoilNumber(self, 5):
                    _setDialogIndex(9)
                else:
                    return
            elif dialogIndex[0] == 4:
                self.topCurveFunction = self._d(2, "af_d2c_textbox_1").text()
                self.bottomCurveFunction = self._d(2, "af_d2c_textbox_2").text()
                if not self._d(4, "af_d2c_radio_2").isChecked():
                    self.airfoilProfileType = 1
                    if _validateFunction(self, 1):
                        _setDialogIndex(9)
                    else:
                        return
                else:
                    self.airfoilProfileType = 2
                    if _validateFunction(self, 2):
                        _setDialogIndex(9)
                    else:
                        return
            elif dialogIndex[0] == 5:
                if self._d(4, "af_d2d_radio_1").isChecked():
                    self.importFrom = 1
                    _setDialogIndex(6)
                else:
                    self.importFrom = 2
                    _setDialogIndex(7)
                if self._d(5, "af_d2d_checkbox").isChecked():
                    self.mirroring = True
                else:
                    self.mirroring = False
            elif dialogIndex[0] == 6:
                tempVar1 = self._d(6, "af_d2d1a_spinBox_1").value()
                tempVar2 = self._d(6, "af_d2d1a_spinBox_2").value()
                tempVar3 = (
                    0 if tempVar1 == 0 or tempVar2 == 0 else tempVar2 - tempVar1 + 1
                )
                if tempVar3 == 0 or tempVar3 >= MIN_DATA_POINTS:
                    self.tempStart = self.lineStart = self._d(
                        6, "af_d2d1a_spinBox_1"
                    ).value()
                    self.tempEnd = self.lineEnd = self._d(
                        6, "af_d2d1a_spinBox_2"
                    ).value()
                    if self._d(4, "af_d2d1a_radio_1").isChecked():
                        self.decimalType = 1
                    else:
                        self.decimalType = 2
                    _setDialogIndex(8)
                else:
                    setAlertBox(
                        "There must be a minimum of "
                        + str(MIN_DATA_POINTS)
                        + " selected file lines,\nthat is, pairs of data points !",
                        True,
                    )
                    return
            elif dialogIndex[0] == 7:
                tempVar = (
                    self._d(6, "af_d2d1b_spinBox_4").value()
                    - self._d(6, "af_d2d1b_spinBox_3").value()
                    + 1
                )
                if tempVar >= MIN_DATA_POINTS:
                    if (
                        self._d(6, "af_d2d1b_spinBox_1").value()
                        == self._d(6, "af_d2d1b_spinBox_2").value()
                    ):
                        self.col1 = self._d(6, "af_d2d1b_spinBox_1").value()
                        self.col2 = self._d(6, "af_d2d1b_spinBox_2").value()
                        self.tempStart = self.row1 = self._d(
                            6, "af_d2d1b_spinBox_3"
                        ).value()
                        self.tempEnd = self.row2 = self._d(
                            6, "af_d2d1b_spinBox_4"
                        ).value()
                        if self._d(4, "af_d2d1b_radio_1").isChecked():
                            self.decimalType = 1
                        else:
                            self.decimalType = 2
                        _setDialogIndex(8)
                    else:
                        setAlertBox("The two file columns cannot be the same !", True)
                        return
                else:
                    setAlertBox(
                        "There must be a minimum of "
                        + str(MIN_DATA_POINTS)
                        + " selected file rows,\nthat is, pairs of data points !",
                        True,
                    )
                    return
            elif dialogIndex[0] == 8:
                if self.loadSuccess:
                    _setDialogIndex(9)
                else:
                    setAlertBox(
                        "Cannot proceed further with an invalid/null file !", True
                    )
                    return
        self._close()
        self._createDialogs()

    def _okay(self):
        """
        This function closes an open dialog box, and
        reverts back to the previous dialog box.
        This function is called when the 'Okay' button is clicked.
        """
        global dialogIndex
        if dialogIndex[0] == 10:
            dialogIndex[0] = dialogIndex[10]
        self._close()
        self._createDialogs()

    def _loadFile(self):
        """
        This function open up the file loader with custom settings.
        This function is called when the 'Load File' button from the.
        'AeroFoil_FileLoad_Dialog' is clicked.
        This function calls the '_validateFile' function/method
        post-loading to verify the file's contents, and then
        notifies the user whether or not the file load was successful.
        """
        fileType = ""
        homeDirPath = str(Path.home())
        if self.importFrom == 1:
            fileType = "Text Files (*.dat)"
        elif self.importFrom == 2:
            fileType = "CSV Files (*.dat)"
        self.loadedFilePath = PySide.QtGui.QFileDialog.getOpenFileName(
            None, "Load 'Airfoil Points' Data File", homeDirPath, fileType
        )
        try:
            self.loadedFile.close()
        except Exception:
            pass
        try:
            self.loadedFile = open(self.loadedFilePath[0], "r")
        except Exception:
            self.loadedFile = ""
        if self.loadedFile == "":
            setAlertBox("No file has been selected!", True)
        else:
            if _validateFile(self):
                self.loadSuccess = True
                if self.mirroring and not self.canMirror:
                    setAlertBox(
                        "Airfoil profile is complete and cannot be mirrored.", False
                    )
            else:
                self.loadSuccess = False
        self._close()
        self._createDialogs()

    def _startCreating(self):
        """
        This function begins the airfoil creation process.
        This function accumulates and stores the final dialog's input data.
        This function also notifies the user whether or not the entire
        'AeroFoil' procedure has been successfully completed.
        This function is called when the 'Create AeroFoil' button from the
        'AeroFoil_Final_Dialog' is clicked.
        This function is responsible for launching the second (Top) macro call.
        """
        global UNITSCONVERSION
        global MIN_CHORD_LENGTH_MM
        if self._d(5, "af_d3_checkbox_1").isChecked():
            self.refine = True
            self.refineParam = self._d(6, "af_d3_spinbox_1").value()
        if self._d(5, "af_d3_checkbox_2").isChecked():
            self.multi = True
            self.multiParam = self._d(6, "af_d3_spinbox_2").value()
        if self._d(5, "af_d3_checkbox_5").isChecked():
            self.closed_ = True
        if self._d(5, "af_d3_checkbox_3").isChecked():
            self.splitCurve = True
            self.splitCurveMode = 1
        if self._d(5, "af_d3_checkbox_4").isChecked():
            self.splitCurve = True
            self.splitCurveMode = 2
        if self._d(5, "af_d3_checkbox_6").isChecked():
            self.defaultEndPoints = True
        if self._d(4, "af_d3_radio_1").isChecked():
            self.workbench = 1
            if self._d(4, "af_d3_radio_1a").isChecked():
                self.curveType = 1
            else:
                self.curveType = 2
        else:
            self.workbench = 2
            if self._d(4, "af_d3_radio_2a").isChecked():
                self.curveType = 1
            else:
                self.curveType = 2
        self.chordLength = self._d(7, "af_d3_spinbox_3").value()
        self.chordUnits = self._d(3, "af_d3_combobox").currentIndex() + 1
        chordLength_conv = self.chordLength * UNITSCONVERSION[self.chordUnits]
        if chordLength_conv >= MIN_CHORD_LENGTH_MM:
            if _prepareAeroFoil(self):
                if AeroFoil_generate(self):
                    self._close()
                    alertBox = QtGui.QMessageBox(
                        QtGui.QMessageBox.Warning,
                        "AeroFoil",
                        "The process has been completed successfully !",
                    )
                    alertBox.setWindowModality(QtCore.Qt.ApplicationModal)
                    alertBox.exec_()
                    app.Console.PrintMessage(
                        "\nThe AeroFoil process has been completed successfully !\n"
                    )
                    return
            setAlertBox(
                "Unexpected error has occurred while processing !\nPlease report.", True
            )
            self.progressBar_.setEnabled(False)
            self.progressBar_.setValue(0)
            app.Console.PrintError(
                "\nUnexpected error has occurred while processing! Please report.\n"
            )
        else:
            setAlertBox(
                "Airfoil chord length cannot be less than "
                + str(MIN_CHORD_LENGTH_MM)
                + "mm !",
                True,
            )

# Other Design Functions
# ------------------------------------------------------------------------------------------

    def _af_d2c_radio_toggled(self):
        if self._d(4, "af_d2c_radio_1").isChecked():
            self.airfoilProfileType = 1
            self._d(2, "af_d2c_textbox_2").setEnabled(False)
        else:
            self.airfoilProfileType = 2
            self._d(2, "af_d2c_textbox_2").setEnabled(True)

    def _af_d3_spinbox_1_toggled(self):
        global MAX_REFINE_PARAM
        if not self.maxRefineParamWarned:
            if self._d(6, "af_d3_spinbox_1").value() > MAX_REFINE_PARAM:
                setAlertBox(
                    "Increase in refinement parameter leads to increase\nin time and memory usage.",
                    False,
                )
                self.maxRefineParamWarned = True

    def _af_d3_spinbox_2_toggled(self):
        global MAX_QUANTITY_PARAM
        if not self.maxQuantityParamWarned:
            if self._d(6, "af_d3_spinbox_2").value() > MAX_QUANTITY_PARAM:
                setAlertBox(
                    "Increase in quantity parameter leads to increase\nin time and memory usage.",
                    False,
                )
                self.maxQuantityParamWarned = True

    def _af_d3_checkbox_1_toggled(self):
        self._d(6, "af_d3_spinbox_1").setValue(2)
        if self._d(5, "af_d3_checkbox_1").isChecked():
            self._d(6, "af_d3_spinbox_1").setEnabled(True)
        else:
            self._d(6, "af_d3_spinbox_1").setEnabled(False)

    def _af_d3_checkbox_2_toggled(self):
        self._d(6, "af_d3_spinbox_2").setValue(2)
        if self._d(5, "af_d3_checkbox_2").isChecked():
            self._d(6, "af_d3_spinbox_2").setEnabled(True)
        else:
            self._d(6, "af_d3_spinbox_2").setEnabled(False)

    def _af_d3_checkbox_5_toggled(self):
        self._d(4, "af_d3_radio_1").setChecked(True)
        self._d(4, "af_d3_radio_1a").setChecked(True)
        self._d(4, "af_d3_radio_2a").setChecked(True)
        self._d(4, "af_d3_radio_1a").setEnabled(True)
        self._d(4, "af_d3_radio_1b").setEnabled(True)
        self._d(4, "af_d3_radio_2a").setEnabled(False)
        self._d(4, "af_d3_radio_2b").setEnabled(False)
        if self._d(5, "af_d3_checkbox_5").isChecked():
            self.closed_ = True
            self._d(4, "af_d3_radio_1").setEnabled(False)
            self._d(4, "af_d3_radio_2").setEnabled(False)
            self._d(5, "af_d3_checkbox_3").setEnabled(False)
            self._d(5, "af_d3_checkbox_4").setEnabled(False)
            self._d(5, "af_d3_checkbox_6").setEnabled(False)
        else:
            if self.closed_:
                self._d(5, "af_d3_checkbox_3").setEnabled(True)
                self._d(5, "af_d3_checkbox_4").setEnabled(True)
                self._d(5, "af_d3_checkbox_6").setEnabled(True)
            self.closed_ = False
            self._d(4, "af_d3_radio_1").setEnabled(True)
            self._d(4, "af_d3_radio_2").setEnabled(True)

    def _af_d3_checkbox_3_toggled(self):
        if self._d(5, "af_d3_checkbox_3").isChecked():
            self._d(5, "af_d3_checkbox_5").setEnabled(False)
            self._d(5, "af_d3_checkbox_6").setEnabled(True)
            self._d(5, "af_d3_checkbox_4").setChecked(False)
        else:
            self._d(5, "af_d3_checkbox_5").setEnabled(True)
            self._d(5, "af_d3_checkbox_6").setEnabled(False)
            self._d(5, "af_d3_checkbox_6").setChecked(False)
        self._d(5, "af_d3_checkbox_5").setChecked(False)
        self._af_d3_checkbox_5_toggled()

    def _af_d3_checkbox_4_toggled(self):
        if self._d(5, "af_d3_checkbox_4").isChecked():
            self._d(5, "af_d3_checkbox_5").setEnabled(False)
            self._d(5, "af_d3_checkbox_6").setEnabled(True)
            self._d(5, "af_d3_checkbox_3").setChecked(False)
        else:
            self._d(5, "af_d3_checkbox_5").setEnabled(True)
            self._d(5, "af_d3_checkbox_6").setEnabled(False)
            self._d(5, "af_d3_checkbox_6").setChecked(False)
        self._d(5, "af_d3_checkbox_5").setChecked(False)
        self._af_d3_checkbox_5_toggled()

    def _af_d3_radio_toggled(self):
        self._d(4, "af_d3_radio_1a").setChecked(True)
        self._d(4, "af_d3_radio_2a").setChecked(True)
        if self._d(4, "af_d3_radio_1").isChecked():
            self._d(4, "af_d3_radio_1a").setEnabled(True)
            self._d(4, "af_d3_radio_1b").setEnabled(True)
            self._d(4, "af_d3_radio_2a").setEnabled(False)
            self._d(4, "af_d3_radio_2b").setEnabled(False)
        else:
            self._d(4, "af_d3_radio_1a").setEnabled(False)
            self._d(4, "af_d3_radio_1b").setEnabled(False)
            self._d(4, "af_d3_radio_2a").setEnabled(True)
            self._d(4, "af_d3_radio_2b").setEnabled(True)

    def _functionsList(self):
        self.topCurveFunction = self._d(2, "af_d2c_textbox_1").text()
        self.bottomCurveFunction = self._d(2, "af_d2c_textbox_2").text()
        _setDialogIndex(10)
        self._close()
        self._createDialogs()



def _setDialogIndex(index):
    """
    This function sets the appropriate dialog box, when the
    'Next', 'Back', and 'Okay' buttons are clicked.
    This function is NOT responsible for loading any dialog boxes.

    The 'index' argument denotes the next or previous dialog box to go to.
    The 'index' number corresponds to the global variable list 'dialogIndex'
    as well as the dialog names table mentioned in the macro's main DocString.

    The first element in the global variable 'dialogIndex' is the index number
    of the currently open dialog box. The other elements too are eventually
    replaced with the index numbers of the dialog box that was opened prior
    to the current one. This allows the macro to remember its backward
    journey through the various dialog boxes.

    Arguments
    ----------
    index:  A dialog box code (Integer) as listed in the global variable
            'dialogIndex'.
    """
    global dialogIndex
    dialogIndex[index] = dialogIndex[0]
    # Here, the first element which contains the current dialog box
    # index number is assigned to the Nth element, where 'N' is the
    # index number of the next dialog box.
    # This ensures that when the 'Back' button is clicked, the macro
    # can approach the previous dialog box. This way, regardless of 'N',
    # the macro can approach the 1st dialog box by maximum.
    dialogIndex[0] = index
    # Here, the first element is set to the 'index' number argument.
    # This sets the macro to open up a specific next dialog box.
    # The macro then opens up the next dialog box when the
    # '_createDialogs' method from the 'AeroFoilDialog' class is called.

def setAlertBox(message, error):
    """
    This function sets the error and warning pop-up messages.

    Arguments
    ----------
    message: The string-based message to be displayed.
    error:   'True' opens up the 'Critical' message box, and
             'False' opens up the 'Warning' message box.
    """
    msgbox_ = 0
    if error:
        msgbox_ = QtGui.QMessageBox(
            QtGui.QMessageBox.Critical, "AeroFoil - Error Message", message
        )
    else:
        msgbox_ = QtGui.QMessageBox(
            QtGui.QMessageBox.Warning, "AeroFoil - Warning Message", message
        )
    msgbox_.setWindowModality(QtCore.Qt.ApplicationModal)
    msgbox_.exec_()



# Operating and Math Functions
# ------------------------------------------------------------------------------------------

def _prepareAeroFoil(objRef):
    """
    This function utilizes the various user input data as a basis
    for creating a list of refined, verified, and finalized
    airfoil data points to be used later for physical creation.
    This function is called from the '_startCreating' method
    of the 'AeroFoilDialog' class.

    Arguments
    ----------
    objRef: An instance of the 'AeroFoilDialog' object.
    """
    global UNITSCONVERSION
    global NACA_NUMBER_OF_POINTS
    chordLength_conv = objRef.chordLength * UNITSCONVERSION[objRef.chordUnits]
    # Enable Progress Bar
    objRef.progressBar_.setEnabled(True)
    objRef.progressBar_.setValue(0)
    # Generating and Furnishing Points
    if objRef.airfoilType == 1:
        _naca4digit(objRef)
    elif objRef.airfoilType == 2:
        _naca5digit(objRef)
    elif objRef.airfoilType == 3:
        xu_, yu_, xl_, yl_ = [], [], [], []
        n_ = (
            round(NACA_NUMBER_OF_POINTS / 2)
            * ((objRef.refine * (objRef.refineParam - 1)) + 1)
        ) + 1
        for points_i in range(n_):
            xu_.append((points_i / (n_ - 1)) * chordLength_conv)
            xl_.append((points_i / (n_ - 1)) * chordLength_conv)
            try:
                yu_.append(solveFx(objRef.topCurveFunction, xu_[-1]) * chordLength_conv)
                if objRef.airfoilProfileType == 1:
                    yl_.append(
                        -1
                        * solveFx(objRef.topCurveFunction, xu_[-1])
                        * chordLength_conv
                    )
                elif objRef.airfoilProfileType == 2:
                    yl_.append(
                        solveFx(objRef.bottomCurveFunction, xu_[-1]) * chordLength_conv
                    )
            except Exception:
                # Unexpected Error Occurred while Processing
                return False
            if objRef.progressBar_.value() < 50:
                objRef.progressBar_.setValue(round((points_i / (2 * n_)) * 100))
        xl_.reverse()
        yl_.reverse()
        objRef.midIndex1, objRef.midIndex2 = len(xu_) - 1, len(xu_)
        objRef.pointsX, objRef.pointsY = xu_ + xl_, yu_ + yl_
    elif objRef.airfoilType == 4:
        count, tempVar, pointsInLine, pointsInLine_prev = (
            1,
            "",
            [],
            [],
        )
        n_ = len(objRef.loadedFileContents)
        for lineOrRow in objRef.loadedFileContents:
            if objRef.decimalType == 1:
                tempVar = lineOrRow
            elif objRef.decimalType == 2:
                tempVar = (
                    lineOrRow.replace(",", ".")
                    if objRef.importFrom == 1
                    else [element_.replace(",", ".") for element_ in lineOrRow]
                )
            tempVar = tempVar.replace("-.", "-0.")
            tempVar = tempVar.replace(" .", "0.")
            tempVar = "0" + tempVar if tempVar[0] == "." else tempVar
            pointsInLine = (
                re.findall(r"[+-]?\d+(?:\.\d+)?", tempVar)
                if objRef.importFrom == 1
                else re.findall(
                    r"[+-]?\d+(?:\.\d+)?", tempVar[col1 - 1] + " " + tempVar[col2 - 1]
                )
            )
            if objRef.refine and count > 1:
                n_ = (
                    float(pointsInLine[0]) - float(pointsInLine_prev[0])
                ) / objRef.refineParam
                for i in range(objRef.refineParam - 1):
                    tempVar = float(pointsInLine_prev[0]) + n_
                    objRef.pointsX.append(tempVar * chordLength_conv)
                    objRef.pointsY.append(
                        interpolateNum(
                            float(pointsInLine_prev[0]),
                            float(pointsInLine_prev[1]),
                            float(pointsInLine[0]),
                            float(pointsInLine[1]),
                            tempVar,
                        )
                        * chordLength_conv
                    )
            pointsInLine_prev = pointsInLine
            objRef.pointsX.append(float(pointsInLine[0]) * chordLength_conv)
            objRef.pointsY.append(float(pointsInLine[1]) * chordLength_conv)
            if objRef.progressBar_.value() < 50:
                objRef.progressBar_.setValue(round((count / (2 * n_)) * 100))
            count += 1
    if (
        objRef.pointsX[len(objRef.pointsX) - 1] != objRef.pointsX[0]
        or objRef.pointsY[len(objRef.pointsY) - 1] != objRef.pointsY[0]
    ) and not objRef.splitCurve:
        objRef.pointsX.append(objRef.pointsX[0])
        objRef.pointsY.append(objRef.pointsY[0])
    return True



def interpolateNum(x1_, y1_, x2_, y2_, x_):
    """
    This function performs a linear interpolation of any given number.

    Arguments
    ----------
    x1_, y1_, x2_, y2_: X and Y-axis values of a pair of data points.
    x: Input value of one of the axes of the data point sought.
    """
    return y1_ + (((x_ - x1_) * (y2_ - y1_)) / (x2_ - x1_))



def generateName(inputName):
    """
    This function correctly provides a given name/label with
    appropriate and non-dulplicate numbering.
    e.g.  'AeroFoil' results in 'AeroFoil_1' if such a labelled
          object does not exist; else, it becomes 'AeroFoil_2'.

    Arguments
    ----------
    inputName: A non-numbered (simple) name/label
    """
    nameIndex = 1
    while True:
        if (
            not doc.getObjectsByLabel(inputName + "_" + str(nameIndex))
            and not doc.getObjectsByLabel(inputName + "_" + str(nameIndex) + "_Upper")
            and not doc.getObjectsByLabel(inputName + "_" + str(nameIndex) + "_Lower")
        ):
            return inputName + "_" + str(nameIndex)
        nameIndex += 1



def _naca4digit(objRef):
    """
    This function generates a list of airfoil data points
    for a typical NACA 4 Digit airfoil model.
    This function is called from the '_startCreating' method
    of the 'AeroFoilDialog' class.

    Arguments
    ----------
    objRef: An instance of the 'AeroFoilDialog' object.
    """
    global UNITSCONVERSION
    global NACA_NUMBER_OF_POINTS
    chordLength_conv = objRef.chordLength * UNITSCONVERSION[objRef.chordUnits]
    xu_, yu_, xl_, yl_ = [], [], [], []
    yc_ = yt_ = theta_ = 0
    a0_, a1_, a2_, a3_, a4_ = 0.2969, -0.126, -0.3516, 0.2843, -0.1015
    m_, p_, t_ = (
        int(objRef.airfoil4DNumber[0]) / 100,
        int(objRef.airfoil4DNumber[1]) / 10,
        int(objRef.airfoil4DNumber[2] + objRef.airfoil4DNumber[3]) / 100,
    )
    n_ = (
        round(NACA_NUMBER_OF_POINTS / 2)
        * ((objRef.refine * (objRef.refineParam - 1)) + 1)
    ) + 1
    for i in range(n_):
        x_ = i / (n_ - 1)
        yt_ = (
            5
            * t_
            * (
                (a0_ * pow(x_, 0.5))
                + (a1_ * x_)
                + (a2_ * pow(x_, 2))
                + (a3_ * pow(x_, 3))
                + (a4_ * pow(x_, 4))
            )
        )
        if x_ < p_:
            yc_ = (m_ * ((2 * p_ * x_) - (x_ * x_))) / (p_ * p_)
            theta_ = math.degrees(math.atan((2 * m_ * (p_ - x_)) / (p_ * p_)))
        else:
            yc_ = (m_ * (1 - (2 * p_) + (2 * p_ * x_) - (x_ * x_))) / pow(1 - p_, 2)
            theta_ = math.degrees(math.atan((2 * m_ * (p_ - x_)) / pow(1 - p_, 2)))
        xu_.append((x_ - (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)
        yu_.append((yc_ + (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)
        xl_.append((x_ + (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)
        yl_.append((yc_ - (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)
        if objRef.progressBar_.value() < 50:
            objRef.progressBar_.setValue(round((i / (2 * n_)) * 100))
    xl_.reverse()
    yl_.reverse()
    objRef.midIndex1, objRef.midIndex2 = len(xu_) - 1, len(xu_)
    objRef.pointsX, objRef.pointsY = xu_ + xl_, yu_ + yl_



def _naca5digit(objRef):
    """
    This function generates a list of airfoil data points
    for a typical NACA 5 Digit airfoil model.
    This function is called from the '_startCreating' method
    of the 'AeroFoilDialog' class.

    Arguments
    ----------
    objRef: An instance of the 'AeroFoilDialog' object.
    """
    global UNITSCONVERSION
    global NACA_NUMBER_OF_POINTS
    chordLength_conv = objRef.chordLength * UNITSCONVERSION[objRef.chordUnits]
    xu_, yu_, xl_, yl_ = [], [], [], []
    yc_ = yt_ = theta_ = 0
    a0_, a1_, a2_, a3_, a4_ = 0.2969, -0.126, -0.3516, 0.2843, -0.1015
    R_ = [0.0580, 0.1260, 0.2025, 0.2900, 0.3910, 0.1300, 0.2170, 0.3180, 0.4410]
    K1_ = [361.400, 51.640, 15.957, 6.643, 3.230, 51.990, 15.793, 6.520, 3.191]
    K2K1_ = [0, 0, 0, 0, 0, 0.000764, 0.00677, 0.0303, 0.1355]
    index = int(objRef.airfoil5DNumber[1]) - 1 + (4 * int(objRef.airfoil5DNumber[2]))
    r_, k1_, k2k1_, t_ = (
        R_[index],
        K1_[index],
        K2K1_[index],
        int(objRef.airfoil5DNumber[3] + objRef.airfoil5DNumber[4]) / 100,
    )
    n_ = (
        round(NACA_NUMBER_OF_POINTS / 2)
        * ((objRef.refine * (objRef.refineParam - 1)) + 1)
    ) + 1
    for i in range(n_):
        x_ = i / (n_ - 1)
        yt_ = (
            5
            * t_
            * (
                (a0_ * pow(x_, 0.5))
                + (a1_ * x_)
                + (a2_ * pow(x_, 2))
                + (a3_ * pow(x_, 3))
                + (a4_ * pow(x_, 4))
            )
        )
        if int(objRef.airfoil5DNumber[2]) == 0:
            if x_ < r_:
                yc_ = (
                    k1_ * (pow(x_, 3) - (3 * r_ * x_ * x_) + (x_ * r_ * r_ * (3 - r_)))
                ) / 6
                theta_ = math.degrees(
                    math.atan(
                        (k1_ * ((3 * x_ * x_) - (6 * r_ * x_) + (r_ * r_ * (3 - r_))))
                        / 6
                    )
                )
            else:
                yc_ = (k1_ * pow(r_, 3) * (1 - x_)) / 6
                theta_ = math.degrees(math.atan(-(k1_ * pow(r_, 3)) / 6))
        elif int(objRef.airfoil5DNumber[2]) == 1:
            if x_ < r_[int(objRef.airfoil5DNumber[1] + objRef.airfoil5DNumber[2])]:
                yc_ = (
                    k1_
                    * (
                        pow(x_ - r_, 3)
                        - (k2k1_ * x_ * pow(1 - r_, 3))
                        - (x_ * pow(r_, 3))
                        + pow(r_, 3)
                    )
                ) / 6
                theta_ = math.degrees(
                    math.atan(
                        (
                            k1_
                            * (
                                (3 * pow(x_ - r_, 2))
                                - (k2k1_ * pow(1 - r_, 3))
                                - (pow(r_, 3))
                            )
                        )
                        / 6
                    )
                )
            else:
                yc_ = (
                    k1_
                    * (
                        (k2k1_ * pow(x_ - r_, 3))
                        - (k2k1_ * x_ * pow(1 - r_, 3))
                        - (x_ * pow(r_, 3))
                        + pow(r_, 3)
                    )
                ) / 6
                theta_ = math.degrees(
                    math.atan(
                        (
                            k1_
                            * (
                                (3 * k2k1_ * pow(x_ - r_, 2))
                                - (k2k1_ * pow(1 - r_, 3))
                                - (pow(r_, 3))
                            )
                        )
                        / 6
                    )
                )
        xu_.append((x_ - (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)
        yu_.append((yc_ + (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)
        xl_.append((x_ + (yt_ * math.sin(math.radians(theta_)))) * chordLength_conv)
        yl_.append((yc_ - (yt_ * math.cos(math.radians(theta_)))) * chordLength_conv)
        if objRef.progressBar_.value() < 50:
            objRef.progressBar_.setValue(round((i / (2 * n_)) * 100))
    xl_.reverse()
    yl_.reverse()
    objRef.midIndex1, objRef.midIndex2 = len(xu_) - 1, len(xu_)
    objRef.pointsX, objRef.pointsY = xu_ + xl_, yu_ + yl_



def convTrig(mode, inputVal):
    """
    This function converts specific, unconventional trigonometric code
    into a Python-based (Math module) trigonometric code.
    This function is called from the 'solveFx' method.

    Arguments
    ----------
    mode: A code number denoting a specific trignometric function.
    inputVal: An unconventional trigonometric code string.
    """
    if mode == 1:
        return math.sin(math.radians(inputVal))
    if mode == 2:
        return math.cos(math.radians(inputVal))
    if mode == 3:
        return math.tan(math.radians(inputVal))
    if mode == 4:
        return math.degrees(math.asin(inputVal))
    if mode == 5:
        return math.degrees(math.acos(inputVal))
    if mode == 6:
        return math.degrees(math.atan(inputVal))



def solveFx(f_, x_):
    """
    This function generates a list of airfoil data points
    for a typical NACA 4 Digit airfoil model.
    This function is called from the '_validateFunction'
    and the '_startCreating' methods of the
    'AeroFoilDialog' class.

    Arguments
    ----------
    objRef: An instance of the 'AeroFoilDialog' object.
    """
    f_ = f_.replace("x", "x_")
    f_ = f_.replace("^", "**")
    f_ = f_.replace("e", "math.e")
    f_ = f_.replace("pi", "math.pi")
    f_ = f_.replace("ln", "math.log")
    f_ = f_.replace("log", "math.log10")
    f_ = f_.replace("sqrt", "math.sqrt")
    f_ = f_.replace("sin(", "convTrig(1,")
    f_ = f_.replace("cos(", "convTrig(2,")
    f_ = f_.replace("tan(", "convTrig(3,")
    f_ = f_.replace("asin(", "convTrig(4,")
    f_ = f_.replace("acos(", "convTrig(5,")
    f_ = f_.replace("atan(", "convTrig(6,")
    try:
        return eval(f_)
    except Exception:
        return



def _validateAirfoilNumber(objRef, digit):
    """
    This function validates whether or not the inputted NACA airfoil model code
    is valid and existing.
    This function is called from the '_next' method of the 'AeroFoilDialog' class.
    This function is called when the 'Next' button from the 'AeroFoil_NACA4Digit_Dialog'
    or the 'AeroFoil_NACA5Digit_Dialog' is clicked.

    Arguments
    ----------
    objRef: An instance of the 'AeroFoilDialog' object.
    digit:  An integer number denoting the NACA airfoil type.
            Options: 4 or 5.
    """
    global NACA_5_2ND_3RD_DIGITS
    airfoilNumber = ""
    airfoilNumber = objRef.airfoil4DNumber if digit == 4 else objRef.airfoil5DNumber
    if airfoilNumber.isnumeric():
        if len(airfoilNumber) == digit:
            if int(airfoilNumber[-2:]) == 0:
                setAlertBox(
                    "The last two digits of the airfoil code cannot be a\nzero value !",
                    True,
                )
            else:
                if digit == 4:
                    return True
                elif digit == 5:
                    if int(airfoilNumber[0]) == 2:
                        if int(airfoilNumber[2]) <= 1:
                            for numRef in NACA_5_2ND_3RD_DIGITS:
                                if airfoilNumber[1] + airfoilNumber[2] == numRef:
                                    return True
                            if airfoilNumber[2] == 0:
                                setAlertBox(
                                    "The second digit of the airfoil code must be\nbetween one and five, both inclusive !",
                                    True,
                                )
                            elif airfoilNumber[2] == 1:
                                setAlertBox(
                                    "The second digit of the airfoil code must be\nbetween two and five, both inclusive !",
                                    True,
                                )
                        else:
                            setAlertBox(
                                "The third digit of the airfoil code must be either\na zero or a one !",
                                True,
                            )
                    else:
                        setAlertBox(
                            "The first digit of the airfoil code must be a two !", True
                        )
        else:
            setAlertBox(
                "Airfoil code must contain exactly " + str(digit) + " digits !", True
            )
    else:
        setAlertBox("Airfoil code must be numeric !", True)
    objRef.airfoil4DNumber, objRef.airfoil5DNumber = "", ""
    return False



def _validateFunction(objRef, mode):
    """
    This function parses the inputted curve functions, and validates them,
    resulting in whether or not the inputted functions are valid from points
    0 to 1, both inclusive, in the X-axis of a typical graph.
    This function is called from the '_next' method of the 'AeroFoilDialog' class.
    This function is called when the 'Next' button from the 'AeroFoil_CurvesInput_Dialog'
    is clicked.

    Arguments
    ----------
    objRef:   An instance of the 'AeroFoilDialog' object.
    mode:     An integer number specifying the function input mode.
    Options:  '1' denotes that one function has been inputted,
              and the function is to be symmetrically mirrored
              to produce the lower airfoil points.
              '2' denotes that two functions have been inputted,
              one for the upper, and one for the lower airfoil points.
    """
    global FUNCTIONSARRAY
    function = [
        objRef.topCurveFunction.replace(" ", ""),
        objRef.bottomCurveFunction.replace(" ", ""),
    ]
    badFunctionCombinations = [
        "()",
        "(+",
        "(-",
        "(*",
        "(/",
        "(^",
        ")(",
        "+)",
        "-)",
        "*)",
        "/)",
        "^)",
        ".)",
        ").",
        ".(",
        "(.",
        "++",
        "--",
        "**",
        "//",
        "^^",
        "xx",
        "ee",
        "pipi",
        "xe",
        "ex",
        "xpi",
        "pix",
        "epi",
        "pie",
        "x(",
        "e(",
        "pi(",
        ")x",
        ")e",
        ")pi",
        ")ln",
        ")log",
        ")sqrt",
        ")sin",
        ")cos",
        ")tan",
        ")asin",
        ")acos",
        ")atan",
    ]
    modeName = ["Top", "Bottom"]
    for i in range(mode):
        if len(function[i]) > 0:
            if function[i].count("(") == function[i].count(")"):
                tempVar = function[i].replace(",", ".")
                for stringRef in FUNCTIONSARRAY:
                    tempVar = tempVar.replace(stringRef, "")
                if len(tempVar) == 0 or tempVar.isnumeric():
                    badFunction, badFunctionFound = "", False
                    for stringRef in badFunctionCombinations:
                        if function[i].count(stringRef) != 0:
                            badFunction, badFunctionFound = stringRef, True
                            break
                    if not badFunctionFound:
                        try:
                            if mode == 1:
                                if (
                                    solveFx(function[i], 0) >= 0
                                    and solveFx(function[i], 1) >= 0
                                ):
                                    return True
                                else:
                                    setAlertBox(
                                        "Top curve function 'range' should not be less than zero !",
                                        True,
                                    )
                            elif mode == 2 and i == 1:
                                if solveFx(function[i], 0) <= solveFx(
                                    function[i - 1], 0
                                ) and solveFx(function[i], 1) <= solveFx(
                                    function[i - 1], 1
                                ):
                                    return True
                                else:
                                    setAlertBox(
                                        "Top and Bottom curve function 'ranges' should not intersect!",
                                        True,
                                    )
                        except Exception:
                            setAlertBox(
                                modeName[i]
                                + " curve function contains unrecognizable,\ninvalid components !",
                                True,
                            )
                    else:
                        setAlertBox(
                            modeName[i]
                            + " curve function contains this invalidly\nwritten component ::  "
                            + badFunction,
                            True,
                        )
                else:
                    setAlertBox(
                        modeName[i]
                        + " curve function contains one or more\ninvalid, extraneous components !",
                        True,
                    )
            else:
                setAlertBox(
                    modeName[i] + " curve function contains unequal parantheses !", True
                )
        else:
            setAlertBox(modeName[i] + " curve function cannot be empty !", True)
    objRef.topCurveFunction, objRef.bottomCurveFunction = "", ""
    return False



def _validateFile(objRef):
    """
    This function parses the file contents of the inputted file path, and validates them,
    resulting in whether or not the file is valid (that is, contains minimum number of points,
    valid data points structure, etc.)
    This function is called from the '_loadFile' method of the 'AeroFoilDialog' class.

    Arguments
    ----------
    objRef: An instance of the 'AeroFoilDialog' object.
    """
    global MIN_DATA_POINTS
    objRef.midIndex1, objRef.midIndex2 = 0, 0
    i_start, i_end, tempVar, tempStr, count, objRef.canMirror, x_prev, dir_ = (
        0,
        0,
        "",
        "",
        1,
        True,
        0,
        [1, 1],
    )
    i_start, i_end, fileReader_ = (
        (objRef.tempStart, objRef.tempEnd, objRef.loadedFile)
        if objRef.importFrom == 1
        else (objRef.row1, objRef.row2, csv.reader(objRef.loadedFile))
    )
    objRef.loadedFileContents = []
    objRef.loadedFile.seek(0)
    if i_start == 0:
        i_start = i_end = 0
        for lineOrRow in fileReader_:
            if objRef.decimalType == 1:
                tempVar = lineOrRow
            elif objRef.decimalType == 2:
                tempVar = (
                    lineOrRow.replace(",", ".")
                    if objRef.importFrom == 1
                    else [element_.replace(",", ".") for element_ in lineOrRow]
                )
            pointsInLine = (
                re.findall(r"[+-]?\d+(?:\.\d+)?", tempVar)
                if objRef.importFrom == 1
                else re.findall(
                    r"[+-]?\d+(?:\.\d+)?",
                    tempVar[objRef.col1 - 1] + " " + tempVar[objRef.col2 - 1],
                )
            )
            if len(pointsInLine) == 2:
                i_start = count if i_start == 0 else i_start
                objRef.loadedFileContents.append(lineOrRow)
            else:
                if i_start != 0:
                    i_end = count - 1
                    break
            if i_start != 0:
                if tempStr == "":
                    tempStr = "1"
                elif tempStr == "1":
                    dir_[0] = dir_[1]
                    dir_[1] = (float(pointsInLine[0]) - x_prev) / abs(
                        float(pointsInLine[0]) - x_prev
                    )
                    if dir_[0] != dir_[1] and (count - i_start) > 2:
                        if objRef.canMirror:
                            objRef.midIndex1, objRef.midIndex2 = (
                                count - i_start - 1,
                                count - i_start,
                            )
                            swapVar = objRef.loadedFileContents[-1]
                            objRef.loadedFileContents[-1] = objRef.loadedFileContents[
                                -2
                            ]
                            objRef.loadedFileContents.append(swapVar)
                        objRef.canMirror = False
                        tempStr = "0"
                x_prev = float(pointsInLine[0])
            count += 1
        if i_start == 0:
            tempStr = (
                "File Line :: " + str(count)
                if objRef.importFrom == 1
                else "File Row :: " + str(count)
            )
            setAlertBox(
                "File is invalid, or file is of incorrect format !\n" + tempStr, True
            )
            return False
    else:
        for lineOrRow in fileReader_:
            if count >= i_start:
                if objRef.decimalType == 1:
                    tempVar = lineOrRow
                elif objRef.decimalType == 2:
                    tempVar = (
                        lineOrRow.replace(",", ".")
                        if objRef.importFrom == 1
                        else [element_.replace(",", ".") for element_ in lineOrRow]
                    )
                pointsInLine = (
                    re.findall(r"[+-]?\d+(?:\.\d+)?", tempVar)
                    if objRef.importFrom == 1
                    else re.findall(
                        r"[+-]?\d+(?:\.\d+)?",
                        tempVar[objRef.col1 - 1] + " " + tempVar[objRef.col2 - 1],
                    )
                )
                if len(pointsInLine) == 2:
                    objRef.loadedFileContents.append(lineOrRow)
                else:
                    if i_end == 0 and count != 1:
                        count += 1
                        break
                    else:
                        tempStr = (
                            "File Line :: " + str(count)
                            if objRef.importFrom == 1
                            else "File Row :: " + str(count)
                        )
                        setAlertBox(
                            "File is invalid, or file is of incorrect format !\n"
                            + tempStr,
                            True,
                        )
                        return False
                if tempStr == "":
                    tempStr = "1"
                elif tempStr == "1":
                    dir_[0] = dir_[1]
                    dir_[1] = (float(pointsInLine[0]) - x_prev) / abs(
                        float(pointsInLine[0]) - x_prev
                    )
                    if dir_[0] != dir_[1] and (count - i_start) > 2:
                        if objRef.canMirror:
                            objRef.midIndex1, objRef.midIndex2 = (
                                count - i_start - 1,
                                count - i_start,
                            )
                            swapVar = objRef.loadedFileContents[-1]
                            objRef.loadedFileContents[-1] = objRef.loadedFileContents[
                                -2
                            ]
                            objRef.loadedFileContents.append(swapVar)
                        objRef.canMirror = False
                        tempStr = "0"
                x_prev = float(pointsInLine[0])
                if i_end != 0 and count == i_end:
                    count += 1
                    break
            count += 1
    i_end = count - 1
    # if i_end - i_start + 1 >= MIN_DATA_POINTS:
    # return True
    if i_end - i_start + 1 < MIN_DATA_POINTS:
        setAlertBox(
            "There must be a minimum of "
            + str(MIN_DATA_POINTS)
            + " selected file rows,\nthat is, pairs of data points !",
            True,
        )
        return False
    objRef.lineStart, objRef.row1, objRef.lineEnd, objRef.row2 = (
        (i_start, i_start, i_end, i_end)
        if objRef.importFrom == 1
        else (objRef.lineStart, objRef.row1, objRef.lineEnd, objRef.row2)
    )
    objRef.loadedFile.close()
    return True



######################################################################
###----------------------------------------------------------------###
### 		AEROFOIL MACRO CALLS - Bottom (check Top)	   ###
###----------------------------------------------------------------###
###								   ###
###								   ###
###	This is the main macro call. The code below commences 	   ###
###	the AeroFoil GUI interface. This script cannot be 	   ###
###	called externally.					   ###
    								   ###
                                                                   ###
if __name__ == "__main__":					   ###
    AeroFoilDialog()						   ###
                                                                   ###
###----------------------------------------------------------------###
### 		AEROFOIL MACRO CALLS - Bottom (check Top)	   ###
###----------------------------------------------------------------###
######################################################################
